<!DOCTYPE html>
<html lang="en-us">
  <head>

    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    
<meta charset="UTF-8">
<title>Composite aggregation | Elasticsearch Guide [7.7] | Elastic</title>
<link rel="home" href="index.html" title="Elasticsearch Guide [7.7]">
<link rel="up" href="search-aggregations-bucket.html" title="Bucket Aggregations">
<link rel="prev" href="search-aggregations-bucket-children-aggregation.html" title="Children Aggregation">
<link rel="next" href="search-aggregations-bucket-datehistogram-aggregation.html" title="Date histogram aggregation">
<meta name="DC.type" content="Learn/Docs/Elasticsearch/Reference/7.7">
<meta name="DC.subject" content="Elasticsearch">
<meta name="DC.identifier" content="7.7">
<meta name="robots" content="noindex,nofollow">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://cdn.optimizely.com/js/18132920325.js"></script>
    <link rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png">
    <link rel="apple-touch-icon" sizes="60x60" href="/apple-icon-60x60.png">
    <link rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png">
    <link rel="apple-touch-icon" sizes="76x76" href="/apple-icon-76x76.png">
    <link rel="apple-touch-icon" sizes="114x114" href="/apple-icon-114x114.png">
    <link rel="apple-touch-icon" sizes="120x120" href="/apple-icon-120x120.png">
    <link rel="apple-touch-icon" sizes="144x144" href="/apple-icon-144x144.png">
    <link rel="apple-touch-icon" sizes="152x152" href="/apple-icon-152x152.png">
    <link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png">
    <link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32">
    <link rel="icon" type="image/png" href="/android-chrome-192x192.png" sizes="192x192">
    <link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96">
    <link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16">
    <link rel="manifest" href="/manifest.json">
    <meta name="apple-mobile-web-app-title" content="Elastic">
    <meta name="application-name" content="Elastic">
    <meta name="msapplication-TileColor" content="#ffffff">
    <meta name="msapplication-TileImage" content="/mstile-144x144.png">
    <meta name="theme-color" content="#ffffff">
    <meta name="naver-site-verification" content="936882c1853b701b3cef3721758d80535413dbfd">
    <meta name="yandex-verification" content="d8a47e95d0972434">
    <meta name="localized" content="true">
    <meta name="st:robots" content="follow,index">
    <meta property="og:image" content="https://www.elastic.co/static/images/elastic-logo-200.png">
    <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
    <link rel="icon" href="/favicon.ico" type="image/x-icon">
    <link rel="apple-touch-icon-precomposed" sizes="64x64" href="/favicon_64x64_16bit.png">
    <link rel="apple-touch-icon-precomposed" sizes="32x32" href="/favicon_32x32.png">
    <link rel="apple-touch-icon-precomposed" sizes="16x16" href="/favicon_16x16.png">
    <!-- Give IE8 a fighting chance -->
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
    <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
    <link rel="stylesheet" type="text/css" href="/guide/static/styles.css">
  </head>

  <!--© 2015-2021 Elasticsearch B.V. Copying, publishing and/or distributing without written permission is strictly prohibited.-->

  <body>
    <!-- Google Tag Manager -->
    <script>dataLayer = [];</script><noscript><iframe src="//www.googletagmanager.com/ns.html?id=GTM-58RLH5" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
    <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= '//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-58RLH5');</script>
    <!-- End Google Tag Manager -->

    <!-- Global site tag (gtag.js) - Google Analytics -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-12395217-16"></script>
    <script>
      window.dataLayer = window.dataLayer || [];
      function gtag(){dataLayer.push(arguments);}
      gtag('js', new Date());
      gtag('config', 'UA-12395217-16');
    </script>

    <!--BEGIN QUALTRICS WEBSITE FEEDBACK SNIPPET-->
    <script type="text/javascript">
      (function(){var g=function(e,h,f,g){
      this.get=function(a){for(var a=a+"=",c=document.cookie.split(";"),b=0,e=c.length;b<e;b++){for(var d=c[b];" "==d.charAt(0);)d=d.substring(1,d.length);if(0==d.indexOf(a))return d.substring(a.length,d.length)}return null};
      this.set=function(a,c){var b="",b=new Date;b.setTime(b.getTime()+6048E5);b="; expires="+b.toGMTString();document.cookie=a+"="+c+b+"; path=/; "};
      this.check=function(){var a=this.get(f);if(a)a=a.split(":");else if(100!=e)"v"==h&&(e=Math.random()>=e/100?0:100),a=[h,e,0],this.set(f,a.join(":"));else return!0;var c=a[1];if(100==c)return!0;switch(a[0]){case "v":return!1;case "r":return c=a[2]%Math.floor(100/c),a[2]++,this.set(f,a.join(":")),!c}return!0};
      this.go=function(){if(this.check()){var a=document.createElement("script");a.type="text/javascript";a.src=g;document.body&&document.body.appendChild(a)}};
      this.start=function(){var a=this;window.addEventListener?window.addEventListener("load",function(){a.go()},!1):window.attachEvent&&window.attachEvent("onload",function(){a.go()})}};
      try{(new g(100,"r","QSI_S_ZN_emkP0oSe9Qrn7kF","https://znemkp0ose9qrn7kf-elastic.siteintercept.qualtrics.com/WRSiteInterceptEngine/?Q_ZID=ZN_emkP0oSe9Qrn7kF")).start()}catch(i){}})();
    </script><div id="ZN_emkP0oSe9Qrn7kF"><!--DO NOT REMOVE-CONTENTS PLACED HERE--></div>
    <!--END WEBSITE FEEDBACK SNIPPET-->

    <div id="elastic-nav" style="display:none;"></div>
    <script src="https://www.elastic.co/elastic-nav.js"></script>

    <!-- Subnav -->
    <div>
      <div>
        <div class="tertiary-nav d-none d-md-block">
          <div class="container">
            <div class="p-t-b-15 d-flex justify-content-between nav-container">
              <div class="breadcrum-wrapper"><span><a href="/guide/" style="font-size: 14px; font-weight: 600; color: #000;">Docs</a></span></div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <div class="main-container">
      <section id="content">
        <div class="content-wrapper">

          <section id="guide" lang="en">
            <div class="container">
              <div class="row">
                <div class="col-xs-12 col-sm-8 col-md-8 guide-section">
                  <!-- start body -->
                  <div class="page_header">
<strong>IMPORTANT</strong>: No additional bug fixes or documentation updates
will be released for this version. For the latest information, see the
<a href="../current/index.html">current release documentation</a>.
</div>
<div id="content">
<div class="breadcrumbs">
<span class="breadcrumb-link"><a href="index.html">Elasticsearch Guide [7.7]</a></span>
»
<span class="breadcrumb-link"><a href="search-aggregations.html">Aggregations</a></span>
»
<span class="breadcrumb-link"><a href="search-aggregations-bucket.html">Bucket Aggregations</a></span>
»
<span class="breadcrumb-node">Composite aggregation</span>
</div>
<div class="navheader">
<span class="prev">
<a href="search-aggregations-bucket-children-aggregation.html">« Children Aggregation</a>
</span>
<span class="next">
<a href="search-aggregations-bucket-datehistogram-aggregation.html">Date histogram aggregation »</a>
</span>
</div>
<div class="section">
<div class="titlepage"><div><div>
<h2 class="title">
<a id="search-aggregations-bucket-composite-aggregation"></a>Composite aggregation<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/bucket/composite-aggregation.asciidoc">edit</a>
</h2>
</div></div></div>
<p>A multi-bucket aggregation that creates composite buckets from different sources.</p>
<p>Unlike the other <code class="literal">multi-bucket</code> aggregation the <code class="literal">composite</code> aggregation can be used
to paginate <span class="strong strong"><strong>all</strong></span> buckets from a multi-level aggregation efficiently. This aggregation
provides a way to stream <span class="strong strong"><strong>all</strong></span> buckets of a specific aggregation similarly to what
<a class="xref" href="search-request-body.html#request-body-search-scroll" title="Scroll">scroll</a> does for documents.</p>
<p>The composite buckets are built from the combinations of the
values extracted/created for each document and each combination is considered as
a composite bucket.</p>
<p>For instance the following document:</p>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">{
    "keyword": ["foo", "bar"],
    "number": [23, 65, 76]
}</pre>
</div>
<p>... creates the following composite buckets when <code class="literal">keyword</code> and <code class="literal">number</code> are used as values source
for the aggregation:</p>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">{ "keyword": "foo", "number": 23 }
{ "keyword": "foo", "number": 65 }
{ "keyword": "foo", "number": 76 }
{ "keyword": "bar", "number": 23 }
{ "keyword": "bar", "number": 65 }
{ "keyword": "bar", "number": 76 }</pre>
</div>
<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="_values_source_2"></a>Values source<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/bucket/composite-aggregation.asciidoc">edit</a>
</h3>
</div></div></div>
<p>The <code class="literal">sources</code> parameter controls the sources that should be used to build the composite buckets.
The order that the <code class="literal">sources</code> are defined is important because it also controls the order
the keys are returned.</p>
<p>The name given to each sources must be unique.</p>
<p>There are three different types of values source:</p>
<div class="section">
<div class="titlepage"><div><div>
<h4 class="title">
<a id="_terms"></a>Terms<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/bucket/composite-aggregation.asciidoc">edit</a>
</h4>
</div></div></div>
<p>The <code class="literal">terms</code> value source is equivalent to a simple <code class="literal">terms</code> aggregation.
The values are extracted from a field or a script exactly like the <code class="literal">terms</code> aggregation.</p>
<p>Example:</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET /_search
{
    "size": 0,
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "sources" : [
                    { "product": { "terms" : { "field": "product" } } }
                ]
            }
        }
     }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/423.console"></div>
<p>Like the <code class="literal">terms</code> aggregation it is also possible to use a script to create the values for the composite buckets:</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET /_search
{
    "size": 0,
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "sources" : [
                    {
                        "product": {
                            "terms" : {
                                "script" : {
                                    "source": "doc['product'].value",
                                    "lang": "painless"
                                }
                            }
                        }
                    }
                ]
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/424.console"></div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h4 class="title">
<a id="_histogram"></a>Histogram<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/bucket/composite-aggregation.asciidoc">edit</a>
</h4>
</div></div></div>
<p>The <code class="literal">histogram</code> value source can be applied on numeric values to build fixed size
interval over the values. The <code class="literal">interval</code> parameter defines how the numeric values should be
transformed. For instance an <code class="literal">interval</code> set to 5 will translate any numeric values to its closest interval,
a value of <code class="literal">101</code> would be translated to <code class="literal">100</code> which is the key for the interval between 100 and 105.</p>
<p>Example:</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET /_search
{
    "size": 0,
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "sources" : [
                    { "histo": { "histogram" : { "field": "price", "interval": 5 } } }
                ]
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/425.console"></div>
<p>The values are built from a numeric field or a script that return numerical values:</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET /_search
{
    "size": 0,
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "sources" : [
                    {
                        "histo": {
                            "histogram" : {
                                "interval": 5,
                                "script" : {
                                    "source": "doc['price'].value",
                                    "lang": "painless"
                                }
                            }
                        }
                    }
                ]
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/426.console"></div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h4 class="title">
<a id="_date_histogram"></a>Date histogram<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/bucket/composite-aggregation.asciidoc">edit</a>
</h4>
</div></div></div>
<p>The <code class="literal">date_histogram</code> is similar to the <code class="literal">histogram</code> value source except that the interval
is specified by date/time expression:</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET /_search
{
    "size": 0,
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "sources" : [
                    { "date": { "date_histogram" : { "field": "timestamp", "calendar_interval": "1d" } } }
                ]
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/427.console"></div>
<p>The example above creates an interval per day and translates all <code class="literal">timestamp</code> values to the start of its closest intervals.
Available expressions for interval: <code class="literal">year</code>, <code class="literal">quarter</code>, <code class="literal">month</code>, <code class="literal">week</code>, <code class="literal">day</code>, <code class="literal">hour</code>, <code class="literal">minute</code>, <code class="literal">second</code></p>
<p>Time values can also be specified via abbreviations supported by <a class="xref" href="common-options.html#time-units" title="Time units">time units</a> parsing.
Note that fractional time values are not supported, but you can address this by shifting to another
time unit (e.g., <code class="literal">1.5h</code> could instead be specified as <code class="literal">90m</code>).</p>
<p><span class="strong strong"><strong>Format</strong></span></p>
<p>Internally, a date is represented as a 64 bit number representing a timestamp in milliseconds-since-the-epoch.
These timestamps are returned as the bucket keys. It is possible to return a formatted date string instead using
the format specified with the format parameter:</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET /_search
{
    "size": 0,
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "sources" : [
                    {
                        "date": {
                            "date_histogram" : {
                                "field": "timestamp",
                                "calendar_interval": "1d",
                                "format": "yyyy-MM-dd" <a id="CO215-1"></a><i class="conum" data-value="1"></i>
                            }
                        }
                    }
                ]
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/428.console"></div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO215-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>Supports expressive date <a class="xref" href="search-aggregations-bucket-daterange-aggregation.html#date-format-pattern" title="Date Format/Pattern">format pattern</a></p>
</td>
</tr>
</table>
</div>
<p><span class="strong strong"><strong>Time Zone</strong></span></p>
<p>Date-times are stored in Elasticsearch in UTC.  By default, all bucketing and
rounding is also done in UTC. The <code class="literal">time_zone</code> parameter can be used to indicate
that bucketing should use a different time zone.</p>
<p>Time zones may either be specified as an ISO 8601 UTC offset (e.g. <code class="literal">+01:00</code> or
<code class="literal">-08:00</code>)  or as a timezone id, an identifier used in the TZ database like
<code class="literal">America/Los_Angeles</code>.</p>
<p><span class="strong strong"><strong>Offset</strong></span></p>
<p>Use the <code class="literal">offset</code> parameter to change the start value of each bucket by the
specified positive (<code class="literal">+</code>) or negative offset (<code class="literal">-</code>) duration, such as <code class="literal">1h</code> for
an hour, or <code class="literal">1d</code> for a day. See <a class="xref" href="common-options.html#time-units" title="Time units">Time units</a> for more possible time
duration options.</p>
<p>For example, when using an interval of <code class="literal">day</code>, each bucket runs from midnight
to midnight. Setting the <code class="literal">offset</code> parameter to <code class="literal">+6h</code> changes each bucket
to run from 6am to 6am:</p>
<a id="composite-aggregation-datehistogram-offset-example"></a><div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">PUT my_index/_doc/1?refresh
{
  "date": "2015-10-01T05:30:00Z"
}

PUT my_index/_doc/2?refresh
{
  "date": "2015-10-01T06:30:00Z"
}

GET my_index/_search?size=0
{
  "aggs": {
    "my_buckets": {
      "composite" : {
        "sources" : [
          {
            "date": {
              "date_histogram" : {
                "field": "date",
                "calendar_interval": "day",
                "offset": "+6h",
                "format": "iso8601"
              }
            }
          }
        ]
      }
    }
  }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/429.console"></div>
<p>Instead of a single bucket starting at midnight, the above request groups the
documents into buckets starting at 6am:</p>
<div class="pre_wrapper lang-console-result">
<pre class="programlisting prettyprint lang-console-result">{
  ...
  "aggregations": {
    "my_buckets": {
      "after_key": { "date": "2015-10-01T06:00:00.000Z" },
      "buckets": [
        {
          "key": { "date": "2015-09-30T06:00:00.000Z" },
          "doc_count": 1
        },
        {
          "key": { "date": "2015-10-01T06:00:00.000Z" },
          "doc_count": 1
        }
      ]
    }
  }
}</pre>
</div>
<div class="note admon">
<div class="icon"></div>
<div class="admon_content">
<p>The start <code class="literal">offset</code> of each bucket is calculated after <code class="literal">time_zone</code>
adjustments have been made.</p>
</div>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h4 class="title">
<a id="_mixing_different_values_source"></a>Mixing different values source<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/bucket/composite-aggregation.asciidoc">edit</a>
</h4>
</div></div></div>
<p>The <code class="literal">sources</code> parameter accepts an array of values source.
It is possible to mix different values source to create composite buckets.
For example:</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET /_search
{
    "size": 0,
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "sources" : [
                    { "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d" } } },
                    { "product": { "terms": {"field": "product" } } }
                ]
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/430.console"></div>
<p>This will create composite buckets from the values created by two values source, a <code class="literal">date_histogram</code> and a <code class="literal">terms</code>.
Each bucket is composed of two values, one for each value source defined in the aggregation.
Any type of combinations is allowed and the order in the array is preserved
in the composite buckets.</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET /_search
{
    "size": 0,
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "sources" : [
                    { "shop": { "terms": {"field": "shop" } } },
                    { "product": { "terms": { "field": "product" } } },
                    { "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d" } } }
                ]
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/431.console"></div>
</div>

</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="_order"></a>Order<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/bucket/composite-aggregation.asciidoc">edit</a>
</h3>
</div></div></div>
<p>By default the composite buckets are sorted by their natural ordering. Values are sorted
in ascending order of their values. When multiple value sources are requested, the ordering is done per value
source, the first value of the composite bucket is compared to the first value of the other composite bucket and if they are equals the
next values in the composite bucket are used for tie-breaking. This means that the composite bucket
 <code class="literal">[foo, 100]</code> is considered smaller than <code class="literal">[foobar, 0]</code> because <code class="literal">foo</code> is considered smaller than <code class="literal">foobar</code>.
It is possible to define the direction of the sort for each value source by setting <code class="literal">order</code> to <code class="literal">asc</code> (default value)
or <code class="literal">desc</code> (descending order) directly in the value source definition.
For example:</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET /_search
{
    "size": 0,
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "sources" : [
                    { "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d", "order": "desc" } } },
                    { "product": { "terms": {"field": "product", "order": "asc" } } }
                ]
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/432.console"></div>
<p>... will sort the composite bucket in descending order when comparing values from the <code class="literal">date_histogram</code> source
and in ascending order when comparing values from the <code class="literal">terms</code> source.</p>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="_missing_bucket"></a>Missing bucket<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/bucket/composite-aggregation.asciidoc">edit</a>
</h3>
</div></div></div>
<p>By default documents without a value for a given source are ignored.
It is possible to include them in the response by setting <code class="literal">missing_bucket</code> to
<code class="literal">true</code> (defaults to <code class="literal">false</code>):</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET /_search
{
    "size": 0,
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "sources" : [
                    { "product_name": { "terms" : { "field": "product", "missing_bucket": true } } }
                ]
            }
        }
     }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/433.console"></div>
<p>In the example above the source <code class="literal">product_name</code> will emit an explicit <code class="literal">null</code> value
for documents without a value for the field <code class="literal">product</code>.
The <code class="literal">order</code> specified in the source dictates whether the <code class="literal">null</code> values should rank
first (ascending order, <code class="literal">asc</code>) or last (descending order, <code class="literal">desc</code>).</p>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="_size_2"></a>Size<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/bucket/composite-aggregation.asciidoc">edit</a>
</h3>
</div></div></div>
<p>The <code class="literal">size</code> parameter can be set to define how many composite buckets should be returned.
Each composite bucket is considered as a single bucket so setting a size of 10 will return the
first 10 composite buckets created from the values source.
The response contains the values for each composite bucket in an array containing the values extracted
from each value source.</p>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="_pagination"></a>Pagination<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/bucket/composite-aggregation.asciidoc">edit</a>
</h3>
</div></div></div>
<p>If the number of composite buckets is too high (or unknown) to be returned in a single response
it is possible to split the retrieval in multiple requests.
Since the composite buckets are flat by nature, the requested <code class="literal">size</code> is exactly the number of composite buckets
that will be returned in the response (assuming that they are at least <code class="literal">size</code> composite buckets to return).
If all composite buckets should be retrieved it is preferable to use a small size (<code class="literal">100</code> or <code class="literal">1000</code> for instance)
and then use the <code class="literal">after</code> parameter to retrieve the next results.
For example:</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET /_search
{
    "size": 0,
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "size": 2,
                "sources" : [
                    { "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d" } } },
                    { "product": { "terms": {"field": "product" } } }
                ]
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/434.console"></div>
<p>... returns:</p>
<div class="pre_wrapper lang-console-result">
<pre class="programlisting prettyprint lang-console-result">{
    ...
    "aggregations": {
        "my_buckets": {
            "after_key": {
                "date": 1494288000000,
                "product": "mad max"
            },
            "buckets": [
                {
                    "key": {
                        "date": 1494201600000,
                        "product": "rocky"
                    },
                    "doc_count": 1
                },
                {
                    "key": {
                        "date": 1494288000000,
                        "product": "mad max"
                    },
                    "doc_count": 2
                }
            ]
        }
    }
}</pre>
</div>
<p>To get the next set of buckets, resend the same aggregation with the <code class="literal">after</code>
parameter set to the <code class="literal">after_key</code> value returned in the response.
For example, this request uses the <code class="literal">after_key</code> value provided in the previous response:</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET /_search
{
    "size": 0,
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "size": 2,
                 "sources" : [
                    { "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d", "order": "desc" } } },
                    { "product": { "terms": {"field": "product", "order": "asc" } } }
                ],
                "after": { "date": 1494288000000, "product": "mad max" } <a id="CO216-1"></a><i class="conum" data-value="1"></i>
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/435.console"></div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO216-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>Should restrict the aggregation to buckets that sort <span class="strong strong"><strong>after</strong></span> the provided values.</p>
</td>
</tr>
</table>
</div>
<div class="note admon">
<div class="icon"></div>
<div class="admon_content">
<p>The <code class="literal">after_key</code> is <span class="strong strong"><strong>usually</strong></span> the key to the last bucket returned in
the response, but that isn’t guaranteed. Always use the returned <code class="literal">after_key</code> instead
of derriving it from the buckets.</p>
</div>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="_early_termination"></a>Early termination<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/bucket/composite-aggregation.asciidoc">edit</a>
</h3>
</div></div></div>
<p>For optimal performance the <a class="xref" href="index-modules-index-sorting.html" title="Index Sorting">index sort</a> should be set on the index so that it matches
parts or fully the source order in the composite aggregation.
For instance the following index sort:</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">PUT twitter
{
    "settings" : {
        "index" : {
            "sort.field" : ["username", "timestamp"],   <a id="CO217-1"></a><i class="conum" data-value="1"></i>
            "sort.order" : ["asc", "desc"]              <a id="CO217-2"></a><i class="conum" data-value="2"></i>
        }
    },
    "mappings": {
        "properties": {
            "username": {
                "type": "keyword",
                "doc_values": true
            },
            "timestamp": {
                "type": "date"
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/436.console"></div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO217-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>This index is sorted by <code class="literal">username</code> first then by <code class="literal">timestamp</code>.</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO217-2"><i class="conum" data-value="2"></i></a></p>
</td>
<td align="left" valign="top">
<p>…​ in ascending order for the <code class="literal">username</code> field and in descending order for the <code class="literal">timestamp</code> field.</p>
<div class="olist orderedlist">
<ol class="orderedlist">
<li class="listitem">
could be used to optimize these composite aggregations:
</li>
</ol>
</div>
</td>
</tr>
</table>
</div>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET /_search
{
    "size": 0,
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "sources" : [
                    { "user_name": { "terms" : { "field": "user_name" } } }     <a id="CO218-1"></a><i class="conum" data-value="1"></i>
                ]
            }
        }
     }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/437.console"></div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO218-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p><code class="literal">user_name</code> is a prefix of the index sort and the order matches (<code class="literal">asc</code>).</p>
</td>
</tr>
</table>
</div>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET /_search
{
    "size": 0,
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "sources" : [
                    { "user_name": { "terms" : { "field": "user_name" } } }, <a id="CO219-1"></a><i class="conum" data-value="1"></i>
                    { "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d", "order": "desc" } } } <a id="CO219-2"></a><i class="conum" data-value="2"></i>
                ]
            }
        }
     }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/438.console"></div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO219-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p><code class="literal">user_name</code> is a prefix of the index sort and the order matches (<code class="literal">asc</code>).</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO219-2"><i class="conum" data-value="2"></i></a></p>
</td>
<td align="left" valign="top">
<p><code class="literal">timestamp</code> matches also the prefix and the order matches (<code class="literal">desc</code>).</p>
</td>
</tr>
</table>
</div>
<p>In order to optimize the early termination it is advised to set <code class="literal">track_total_hits</code> in the request
to <code class="literal">false</code>. The number of total hits that match the request can be retrieved on the first request
and it would be costly to compute this number on every page:</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET /_search
{
    "size": 0,
    "track_total_hits": false,
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "sources" : [
                    { "user_name": { "terms" : { "field": "user_name" } } },
                    { "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d", "order": "desc" } } }
                ]
            }
        }
     }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/439.console"></div>
<p>Note that the order of the source is important, in the example below switching the <code class="literal">user_name</code> with the <code class="literal">timestamp</code>
would deactivate the sort optimization since this configuration wouldn’t match the index sort specification.
If the order of sources do not matter for your use case you can follow these simple guidelines:</p>
<div class="ulist itemizedlist">
<ul class="itemizedlist">
<li class="listitem">
Put the fields with the highest cardinality first.
</li>
<li class="listitem">
Make sure that the order of the field matches the order of the index sort.
</li>
<li class="listitem">
Put multi-valued fields last since they cannot be used for early termination.
</li>
</ul>
</div>
<div class="warning admon">
<div class="icon"></div>
<div class="admon_content">
<p><a class="xref" href="index-modules-index-sorting.html" title="Index Sorting">index sort</a> can slowdown indexing, it is very important to test index sorting
with your specific use case and dataset to ensure that it matches your requirement. If it doesn’t note that <code class="literal">composite</code>
aggregations will also try to early terminate on non-sorted indices if the query matches all document (<code class="literal">match_all</code> query).</p>
</div>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="_sub_aggregations"></a>Sub-aggregations<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/bucket/composite-aggregation.asciidoc">edit</a>
</h3>
</div></div></div>
<p>Like any <code class="literal">multi-bucket</code> aggregations the <code class="literal">composite</code> aggregation can hold sub-aggregations.
These sub-aggregations can be used to compute other buckets or statistics on each composite bucket created by this
parent aggregation.
For instance the following example computes the average value of a field
per composite bucket:</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET /_search
{
    "size": 0,
    "aggs" : {
        "my_buckets": {
            "composite" : {
                 "sources" : [
                    { "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d", "order": "desc" } } },
                    { "product": { "terms": {"field": "product" } } }
                ]
            },
            "aggregations": {
                "the_avg": {
                    "avg": { "field": "price" }
                }
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/440.console"></div>
<p>... returns:</p>
<div class="pre_wrapper lang-console-result">
<pre class="programlisting prettyprint lang-console-result">{
    ...
    "aggregations": {
        "my_buckets": {
            "after_key": {
                "date": 1494201600000,
                "product": "rocky"
            },
            "buckets": [
                {
                    "key": {
                        "date": 1494460800000,
                        "product": "apocalypse now"
                    },
                    "doc_count": 1,
                    "the_avg": {
                        "value": 10.0
                    }
                },
                {
                    "key": {
                        "date": 1494374400000,
                        "product": "mad max"
                    },
                    "doc_count": 1,
                    "the_avg": {
                        "value": 27.0
                    }
                },
                {
                    "key": {
                        "date": 1494288000000,
                        "product" : "mad max"
                    },
                    "doc_count": 2,
                    "the_avg": {
                        "value": 22.5
                    }
                },
                {
                    "key": {
                        "date": 1494201600000,
                        "product": "rocky"
                    },
                    "doc_count": 1,
                    "the_avg": {
                        "value": 10.0
                    }
                }
            ]
        }
    }
}</pre>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="_pipeline_aggregations"></a>Pipeline aggregations<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/bucket/composite-aggregation.asciidoc">edit</a>
</h3>
</div></div></div>
<p>The composite agg is not currently compatible with pipeline aggregations, nor does it make sense in most cases.
E.g. due to the paging nature of composite aggs, a single logical partition (one day for example) might be spread
over multiple pages.  Since pipeline aggregations are purely post-processing on the final list of buckets,
running something like a derivative on a composite page could lead to inaccurate results as it is only taking into
account a "partial" result on that page.</p>
<p>Pipeline aggs that are self contained to a single bucket (such as <code class="literal">bucket_selector</code>) might be supported in the future.</p>
</div>

</div>
<div class="navfooter">
<span class="prev">
<a href="search-aggregations-bucket-children-aggregation.html">« Children Aggregation</a>
</span>
<span class="next">
<a href="search-aggregations-bucket-datehistogram-aggregation.html">Date histogram aggregation »</a>
</span>
</div>
</div>

                  <!-- end body -->
                </div>
                <div class="col-xs-12 col-sm-4 col-md-4" id="right_col">
                  <div id="rtpcontainer" style="display: block;">
                    <div class="mktg-promo">
                      <h3>Most Popular</h3>
                      <ul class="icons">
                        <li class="icon-elasticsearch-white"><a href="https://www.elastic.co/webinars/getting-started-elasticsearch?baymax=default&amp;elektra=docs&amp;storm=top-video">Get Started with Elasticsearch: Video</a></li>
                        <li class="icon-kibana-white"><a href="https://www.elastic.co/webinars/getting-started-kibana?baymax=default&amp;elektra=docs&amp;storm=top-video">Intro to Kibana: Video</a></li>
                        <li class="icon-logstash-white"><a href="https://www.elastic.co/webinars/introduction-elk-stack?baymax=default&amp;elektra=docs&amp;storm=top-video">ELK for Logs &amp; Metrics: Video</a></li>
                      </ul>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </section>

        </div>


<div id="elastic-footer"></div>
<script src="https://www.elastic.co/elastic-footer.js"></script>
<!-- Footer Section end-->

      </section>
    </div>

<script src="/guide/static/jquery.js"></script>
<script type="text/javascript" src="/guide/static/docs.js"></script>
<script type="text/javascript">
  window.initial_state = {}</script>
  </body>
</html>
